home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 3 / CD ACTUAL 3.iso / linux / incoming / jstools-.6v3 / jstools- / jstools-tk3.6v3.0 / lib / jeditmodes / tcl-mode.tcl < prev   
Encoding:
Text File  |  1995-02-09  |  9.4 KB  |  334 lines

  1. ######################################################################
  2. # ~/.tk/edittkmodes/tcl-mode.tcl - mode for editing Tcl code
  3. ######################################################################
  4.  
  5. # things it handles well:
  6. #
  7. # frame .foo \
  8. #   -width 10 -height 20 \
  9. #   -background blue
  10. # proc foo {} {
  11. #   global bar
  12. #   if $bar {   ; # comment
  13. #     baz
  14. #   } else { }
  15. # }
  16. # format {
  17. #   %d dollars,
  18. #   %d cents.
  19. # } $dollars $cents
  20. #
  21. # things it handles badly:
  22. #
  23. # proc foo {} { global bar
  24. #   if $bar {
  25. #     baz
  26. #   } else {
  27. #   }    ;# nothing but newline between open and close braces
  28. # }
  29. # set foo {
  30. #   bar
  31. #   baz} ;# close brace not at beginning of line
  32. # catch {
  33. #   $t tag configure comment -foreground grey50 \
  34. #     -font -*-lucida-medium-r-normal-sans-10-100-*
  35. # } ;# last line before close brace is a continuation
  36.  
  37. proc mode:tcl:init { t } {
  38.   global JEDIT_MODEPREFS
  39.   
  40.   j:read_prefs -array JEDIT_MODEPREFS -prefix tcl \
  41.     -directory ~/.tk/jeditmodes -file tcl-defaults {
  42.     {textfont default}
  43.     {textwidth 80}
  44.     {textheight 24}
  45.     {textwrap char}
  46.     {sabbrev 0}
  47.     {dabbrev 0}
  48.     {autobreak 0}
  49.     {autoindent 1}
  50.     {parenflash 1}
  51.     {savestate 0}
  52.     {buttonbar 1}
  53.     {menu,editor 1}
  54.     {menu,file 1}
  55.     {menu,edit 1}
  56.     {menu,prefs 0}
  57.     {menu,abbrev 1}
  58.     {menu,filter 1}
  59.     {menu,format 0}
  60.     {menu,display 0}
  61.     {menu,mode1 1}
  62.     {menu,mode2 1}
  63.     {menu,user 1}
  64.   }
  65.   
  66.   # There should be a mode-specific preferences panel for this:
  67.   global TCL_MODE
  68.   set TCL_MODE(quick) 1            ;# if 1, no comment highlighting
  69.   set TCL_MODE(indent) 2        ;# number of chars per nesting level
  70.   
  71.   ######################################################################
  72.   # tags
  73.   
  74.   catch {
  75.     $t tag configure comment -foreground grey50 \
  76.       -font -*-lucida-medium-r-normal-sans-10-100-*
  77.   }
  78. }
  79.  
  80. ######################################################################
  81. # make Tcl menu
  82. ######################################################################
  83.  
  84. proc mode:tcl:mkmenu1 { menu t } {
  85.   menubutton $menu -text {Tcl} -menu $menu.m
  86.   
  87.   menu $menu.m
  88.   $menu.m add command -label {Comment with #} \
  89.     -command "mode:tcl:prefix {# } $t"
  90.   $menu.m add command -label {Comment with ###} \
  91.     -command "mode:tcl:prefix {### } $t"
  92.   $menu.m add command -label {Uncomment} \
  93.     -command "mode:tcl:uncomment $t"
  94.   $menu.m add command -label {Make Border} \
  95.     -accelerator {[3]} \
  96.     -command "mode:tcl:border $t"
  97.   
  98.   bind $t <Meta-Key-3> "mode:tcl:border $t"
  99. }
  100.  
  101. ######################################################################
  102. # make Procs menu (mostly done by mode:tcl:mkprocsmenu)
  103. ######################################################################
  104.  
  105. proc mode:tcl:mkmenu2 {menu t} {
  106.   menubutton $menu -text {Procs} -menu $menu.m
  107.   
  108.   menu $menu.m -postcommand "mode:tcl:mkprocsmenu $menu $t"
  109. }
  110.  
  111. ######################################################################
  112. # button bar
  113. ######################################################################
  114.  
  115. proc mode:tcl:mkbuttons { w t } {
  116.   j:buttonbar $w -pady 2 -buttons [format {
  117.     {save Save {jedit:cmd:save %s}}
  118.     {hash {#} {mode:tcl:prefix "# " %s}}
  119.     {hashes {###} {mode:tcl:prefix "### " %s}}
  120.     {unhash {Un-#} {mode:tcl:uncomment %s}}
  121.     {border {Border} {mode:tcl:border %s}}
  122.   } $t $t $t $t $t]
  123.   return $w
  124. }
  125.  
  126. ######################################################################
  127. # adjust indentation based on nesting
  128. ######################################################################
  129.  
  130. proc mode:tcl:autoindent { t } {
  131.   global TCL_MODE
  132.   
  133.   set indentlevel 0
  134.   set current [$t get {insert linestart} {insert}]
  135.   set prevline [$t get {insert -1lines linestart} {insert -1lines lineend}]
  136.   set antepenult [$t get {insert -2lines linestart} {insert -2lines lineend}]
  137.   
  138.   set indent ""
  139.   regexp "^  *" $prevline indent
  140.   set indentlevel [string length $indent]
  141.   
  142.   set anteindent ""
  143.   regexp "^  *" $antepenult anteindent
  144.   set antelevel [string length $anteindent]
  145.   
  146.   set close "^\[ \t\]*\}"            ;# brace at beginning of line
  147.   if {[regexp $close $prevline]} {
  148.     if {$indentlevel == $antelevel && $indentlevel >= $TCL_MODE(indent)} {
  149.       # change current indentation level:
  150.       incr indentlevel -$TCL_MODE(indent)
  151.       # and adjust previous line's indentation:
  152.       $t delete {insert -1lines linestart} \
  153.         "insert -1lines linestart +$TCL_MODE(indent)chars"
  154.     }
  155.   }
  156.   set comment "\{\[ \t;\]*#\[^\}\]*$"        ;# brace followed by comment
  157.   if {[regexp "\{$" $prevline] || [regexp $comment $prevline]} {
  158.     incr indentlevel $TCL_MODE(indent)
  159.   }
  160.   if {[string match {*[\]} $prevline]} {    ;# line continued
  161.     if {![string match {*[\]} $antepenult]} {
  162.       incr indentlevel $TCL_MODE(indent)
  163.     }
  164.   } else {
  165.     if {[string match {*[\]} $antepenult]} {
  166.       # last line was a continuation, but this one isn't
  167.       incr indentlevel -$TCL_MODE(indent)
  168.     }
  169.   }
  170.   if {$indentlevel < 0} {set indentlevel 0}
  171.   
  172.   for {set i 0} {$i < $indentlevel} {incr i} {
  173.     $t insert insert " "
  174.   }
  175. }
  176.  
  177. ######################################################################
  178. # highlight comments in previous line
  179. ######################################################################
  180.  
  181. proc mode:tcl:post_returnkey_hook { t } {
  182.   set lineno [lindex [split [$t index insert] .] 0]
  183.   if {$lineno == 1} {return 0}
  184.   mode:tcl:tag_line [expr {$lineno - 1}] $t
  185. }
  186.  
  187. ######################################################################
  188. # parse/tag all lines
  189. ######################################################################
  190.  
  191. proc mode:tcl:post_read_hook { filename t } {
  192.   set lastline [lindex [split [$t index end] .] 0]
  193.   for {set i 1} {$i < $lastline} {incr i} {
  194.     mode:tcl:tag_line $i $t
  195.   }
  196. }
  197.  
  198. ######################################################################
  199. # remember insert so we can scan pasted lines
  200. ######################################################################
  201.  
  202. proc mode:tcl:pre_paste_hook { t } {
  203.   global pre_paste_line
  204.   set pre_paste_line [lindex [split [$t index insert] .] 0]
  205. }
  206.  
  207. ######################################################################
  208. # scan all the pasted lines
  209. ######################################################################
  210.  
  211. proc mode:tcl:post_paste_hook { t } {
  212.   global pre_paste_line
  213.   set post_paste_line [lindex [split [$t index insert] .] 0]
  214.   for {set i $pre_paste_line} {$i < $post_paste_line} {incr i} {
  215.     mode:tcl:tag_line $i $t
  216.   }
  217. }
  218.  
  219. ######################################################################
  220. # remember insert so we can scan pasted lines
  221. ######################################################################
  222.  
  223. proc mode:tcl:pre_xpaste_hook { t } {
  224.   global pre_paste_line
  225.   set pre_paste_line [lindex [split [$t index insert] .] 0]
  226. }
  227.  
  228. ######################################################################
  229. # scan all the pasted lines
  230. ######################################################################
  231.  
  232. proc mode:tcl:post_xpaste_hook { t } {
  233.   global pre_paste_line
  234.   set post_paste_line [lindex [split [$t index insert] .] 0]
  235.   for {set i $pre_paste_line} {$i < $post_paste_line} {incr i} {
  236.     mode:tcl:tag_line $i $t
  237.   }
  238. }
  239.  
  240. ######################################################################
  241. # miscellaneous procedures:
  242.  
  243. proc mode:tcl:prefix { prefix t } {
  244.   jedit:text_regsub $t \
  245.     [format {(^|%s)} "\n"] \
  246.     [format {\1%s} $prefix]
  247. }
  248.  
  249. proc mode:tcl:uncomment { t } {
  250.   jedit:text_regsub $t \
  251.     [format {(^|%s)#* } "\n"] \
  252.     {\1}
  253. }
  254.  
  255. proc mode:tcl:border { t } {
  256.   j:text:insert_string $t \
  257.     "######################################################################\n"
  258. }
  259.   
  260. ######################################################################
  261. # find all the procedures and add them to mode2 menu
  262. #   this is the -command parameter for .menu.mode2
  263. ######################################################################
  264.  
  265. proc mode:tcl:mkprocsmenu {menu t} {
  266.   set lines [lindex [split [$t index end] .] 0]
  267.   set linelist {}
  268.   
  269.   for {set line 0} {$line <= $lines} {incr line} {
  270.     if [string match "proc\[ \t\]" [$t get $line.0 "$line.0 +5chars"]] {
  271.       lappend linelist $line
  272.     }
  273.   }
  274.   
  275.   $menu.m delete 0 last
  276.   
  277.   $menu.m add command -label "Top" -command "
  278.     $t mark set insert 0.0
  279.     $t yview -pickplace insert
  280.   "
  281.   $menu.m add separator
  282.   
  283.   foreach line $linelist {
  284.     set text [$t get $line.0 "$line.0 lineend"]
  285.     regsub "^proc\[ \t]*(\[^ \t\]*).*" $text {\1} text
  286.     $menu.m add command -label "$text" -command "
  287.       $t mark set insert $line.0
  288.       $t yview -pickplace insert
  289.     "
  290.   }
  291.   
  292.   $menu.m add separator
  293.   $menu.m add command -label "End" -command "
  294.     $t mark set insert end
  295.     $t yview -pickplace insert
  296.   "
  297.   
  298.   update
  299. }
  300.  
  301. ######################################################################
  302. # highlight comments
  303. ######################################################################
  304. #### THIS IS TOO SLOW!
  305. proc mode:tcl:tag_line { lineno t } {
  306.   global TCL_MODE
  307.   if $TCL_MODE(quick) {return 0}
  308.   
  309.   # make sure there's no highlighting already:
  310.   $t tag remove comment "$lineno.0" "$lineno.0 lineend"
  311.  
  312.   set line [$t get "$lineno.0" "$lineno.0 lineend"]
  313.   
  314.   # if entire line is comment:
  315.   if [regexp -indices "^\[ ;\t]*(#.*)" $line foo indices] {
  316.     set first "$lineno.0 +[lindex $indices 0]chars"
  317.     set last "$lineno.0 lineend"
  318.     $t tag add comment $first $last
  319.     return 0
  320.   }
  321.   # if comment immediately follows a semicolon:
  322.   if [regexp -indices "(;#.*)" $line foo indices] {
  323.     set first "$lineno.0 +[lindex $indices 0]chars"
  324.     set last "$lineno.0 lineend"
  325.     $t tag add comment $first $last
  326.     return 0
  327.   }
  328. }
  329.  
  330.